package org.xwalk.core.internal;

import java.io.Serializable;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class XWalkNavigationHistoryBridge extends XWalkNavigationHistoryInternal {
    private XWalkCoreBridge coreBridge;
    private Object wrapper;

    public Object getWrapper() {
        return wrapper;
    }

    private ReflectMethod enumDirectionClassValueOfMethod = new ReflectMethod();

    private Object ConvertDirectionInternal(DirectionInternal type) {
        return enumDirectionClassValueOfMethod.invoke(type.toString());
    }


    private XWalkNavigationHistoryInternal internal;

    XWalkNavigationHistoryBridge(XWalkNavigationHistoryInternal internal) {
        this.internal = internal;
        reflectionInit();
    }

    @Override
    public int size() {
        if (sizeMethod == null || sizeMethod.isNull()) {
            return sizeSuper();
        } else {
            return (Integer)sizeMethod.invoke();
        }
    }

    public int sizeSuper() {
        int ret;
        if (internal == null) {
            ret = super.size();
        } else {
            ret = internal.size();
        }
        
        return ret;
    }

    private ReflectMethod sizeMethod = new ReflectMethod(null, "size");

    @Override
    public boolean hasItemAt(int index) {
        if (hasItemAtintMethod == null || hasItemAtintMethod.isNull()) {
            return hasItemAtSuper(index);
        } else {
            return (Boolean)hasItemAtintMethod.invoke(index);
        }
    }

    public boolean hasItemAtSuper(int index) {
        boolean ret;
        if (internal == null) {
            ret = super.hasItemAt(index);
        } else {
            ret = internal.hasItemAt(index);
        }
        
        return ret;
    }

    private ReflectMethod hasItemAtintMethod = new ReflectMethod(null, "hasItemAt");

    @Override
    public XWalkNavigationItemInternal getItemAt(int index) {
        if (getItemAtintMethod == null || getItemAtintMethod.isNull()) {
            return getItemAtSuper(index);
        } else {
            return (XWalkNavigationItemBridge)coreBridge.getBridgeObject(getItemAtintMethod.invoke(index));
        }
    }

    public XWalkNavigationItemBridge getItemAtSuper(int index) {
        XWalkNavigationItemInternal ret;
        if (internal == null) {
            ret = super.getItemAt(index);
        } else {
            ret = internal.getItemAt(index);
        }
        if (ret == null) return null;
        return (ret instanceof XWalkNavigationItemBridge ? ((XWalkNavigationItemBridge) ret ) : new XWalkNavigationItemBridge(ret));
    }

    private ReflectMethod getItemAtintMethod = new ReflectMethod(null, "getItemAt");

    @Override
    public XWalkNavigationItemInternal getCurrentItem() {
        if (getCurrentItemMethod == null || getCurrentItemMethod.isNull()) {
            return getCurrentItemSuper();
        } else {
            return (XWalkNavigationItemBridge)coreBridge.getBridgeObject(getCurrentItemMethod.invoke());
        }
    }

    public XWalkNavigationItemBridge getCurrentItemSuper() {
        XWalkNavigationItemInternal ret;
        if (internal == null) {
            ret = super.getCurrentItem();
        } else {
            ret = internal.getCurrentItem();
        }
        if (ret == null) return null;
        return (ret instanceof XWalkNavigationItemBridge ? ((XWalkNavigationItemBridge) ret ) : new XWalkNavigationItemBridge(ret));
    }

    private ReflectMethod getCurrentItemMethod = new ReflectMethod(null, "getCurrentItem");

    @Override
    public boolean canGoBack() {
        if (canGoBackMethod == null || canGoBackMethod.isNull()) {
            return canGoBackSuper();
        } else {
            return (Boolean)canGoBackMethod.invoke();
        }
    }

    public boolean canGoBackSuper() {
        boolean ret;
        if (internal == null) {
            ret = super.canGoBack();
        } else {
            ret = internal.canGoBack();
        }
        
        return ret;
    }

    private ReflectMethod canGoBackMethod = new ReflectMethod(null, "canGoBack");

    @Override
    public boolean canGoForward() {
        if (canGoForwardMethod == null || canGoForwardMethod.isNull()) {
            return canGoForwardSuper();
        } else {
            return (Boolean)canGoForwardMethod.invoke();
        }
    }

    public boolean canGoForwardSuper() {
        boolean ret;
        if (internal == null) {
            ret = super.canGoForward();
        } else {
            ret = internal.canGoForward();
        }
        
        return ret;
    }

    private ReflectMethod canGoForwardMethod = new ReflectMethod(null, "canGoForward");

    @Override
    public void navigate(DirectionInternal direction, int steps) {
        if (navigateDirectionInternalintMethod == null || navigateDirectionInternalintMethod.isNull()) {
            navigateSuper(direction, steps);
        } else {
            navigateDirectionInternalintMethod.invoke(ConvertDirectionInternal(direction), steps);
        }
    }

    public void navigateSuper(DirectionInternal direction, int steps) {
        if (internal == null) {
            super.navigate(direction, steps);
        } else {
            internal.navigate(direction, steps);
        }
    }

    private ReflectMethod navigateDirectionInternalintMethod = new ReflectMethod(null, "navigate");

    @Override
    public int getCurrentIndex() {
        if (getCurrentIndexMethod == null || getCurrentIndexMethod.isNull()) {
            return getCurrentIndexSuper();
        } else {
            return (Integer)getCurrentIndexMethod.invoke();
        }
    }

    public int getCurrentIndexSuper() {
        int ret;
        if (internal == null) {
            ret = super.getCurrentIndex();
        } else {
            ret = internal.getCurrentIndex();
        }
        
        return ret;
    }

    private ReflectMethod getCurrentIndexMethod = new ReflectMethod(null, "getCurrentIndex");

    @Override
    public void clear() {
        if (clearMethod == null || clearMethod.isNull()) {
            clearSuper();
        } else {
            clearMethod.invoke();
        }
    }

    public void clearSuper() {
        if (internal == null) {
            super.clear();
        } else {
            internal.clear();
        }
    }

    private ReflectMethod clearMethod = new ReflectMethod(null, "clear");


    void reflectionInit() {
        coreBridge = XWalkCoreBridge.getInstance();
        if (coreBridge == null) return;

        ReflectConstructor constructor = new ReflectConstructor(
                coreBridge.getWrapperClass("XWalkNavigationHistory"), Object.class);
        try {
            wrapper = constructor.newInstance(this);
        } catch (UnsupportedOperationException e) {
            return;
        }

        enumDirectionClassValueOfMethod.init(null,
                coreBridge.getWrapperClass("XWalkNavigationHistory$Direction"), "valueOf", String.class);

        sizeMethod.init(wrapper, null,
                "size");
        hasItemAtintMethod.init(wrapper, null,
                "hasItemAt", int.class);
        getItemAtintMethod.init(wrapper, null,
                "getItemAt", int.class);
        getCurrentItemMethod.init(wrapper, null,
                "getCurrentItem");
        canGoBackMethod.init(wrapper, null,
                "canGoBack");
        canGoForwardMethod.init(wrapper, null,
                "canGoForward");
        navigateDirectionInternalintMethod.init(wrapper, null,
                "navigate", coreBridge.getWrapperClass("XWalkNavigationHistory$Direction"), int.class);
        getCurrentIndexMethod.init(wrapper, null,
                "getCurrentIndex");
        clearMethod.init(wrapper, null,
                "clear");
    }
}
